#include "world.h"
#include "engine.h"

namespace sleek
{
    namespace core
    {
        namespace engine
        {
            engine::engine(world* dev) : screen(dev->getDevice()), manager(dev), mom(dev->getDrawManager())
            {
                cm = new node::camera::Camera(screen);
                collision = new btDefaultCollisionConfiguration();
                dispatcher = new btCollisionDispatcher(collision);
                broadphase = new btDbvtBroadphase();
                impulse = new btSequentialImpulseConstraintSolver;
                phy = new btDiscreteDynamicsWorld(dispatcher,broadphase,impulse,collision);
                phy->setGravity(btVector3(0,-9.81f,0));
                //setFog(100.f, 1000.f, 0.35f, texture::pixel(35,35,35,255));
            }
            engine::~engine()
            {
                clear();
                delete phy;
                delete impulse;
                delete broadphase;;
                delete dispatcher;
                delete collision;
                delete cm;
            }
            /* ***************************************** */
            node::Node *engine::addSceneNode(node::Node *t)
            {
                getWorld()->lock();
                nd.push_back(t);
                getWorld()->unlock();
            }
            void engine::removeNode(node::Node *t)
            {
                getWorld()->lock();
                s32 i = nd.linear_search(t);
                if(i == -1 || nd.size() == 0) return;
                nd.erase(i); delete t; t = 0;
                getWorld()->unlock();
            }
            /* ***************************************** */
            void engine::reloadScene()
            {
            }
            void engine::loadScene(const char*)
            {
            }
            void engine::saveScene(const char*)
            {
            }
            void engine::setFog(core::f32 start, core::f32 end, core::f32 density, texture::pixel color)
            {
                GLuint fogfilter = 0;
                GLuint fogMode[] = { GL_EXP, GL_EXP2, GL_LINEAR };
                GLfloat fogColor[4]= { (float)color.getRed()/255, (float)color.getGreen()/255, (float)color.getBlue()/255, 1.0f };

                glFogi(GL_FOG_MODE, fogMode[fogfilter]);
                glFogfv(GL_FOG_COLOR, fogColor);
                glFogf(GL_FOG_DENSITY, 0.35f);
                glHint(GL_FOG_HINT, GL_DONT_CARE);
                glFogf(GL_FOG_START, start);
                glFogf(GL_FOG_END, end);
                glEnable(GL_FOG);
            }
            void engine::clear()
            {
                while(nd.size()) removeNode(getNode(0));
            }
            /* ***************************************** */
            void engine::render()
            {
                glPushMatrix();
                    cm->manage(screen->getCurrentEvent());
                    cm->update();
                    cm->render();
                    for(register u32 i = 0; i<nd.size(); ++i)
                    {
                        node::Node *tmp = nd[i];
                        tmp->render();
                    }
                glPopMatrix();
            }
            void engine::enableDebugDraw(bool a)
            {
                debug_draw = a;
            }
            bool engine::isDebugDraw()
            {
                return debug_draw;
            }
            world *engine::getWorld()
            {
                return manager;
            }
            device::Device *engine::getDevice()
            {
                return screen;
            }
            texture::draw *engine::getDrawManager()
            {
                return mom;
            }
            node::camera::Camera *engine::getCamera()
            {
                return cm;
            }
            btDiscreteDynamicsWorld *engine::getPhysics()
            {
                return phy;
            }
        }
    }
}
